Skip to content

feat: add JSON/XML/Text/Bytes/Stream/Attachment response helpers - #53

Merged
qm012 merged 1 commit into
mainfrom
responder
Aug 31, 2026
Merged

feat: add JSON/XML/Text/Bytes/Stream/Attachment response helpers#53
qm012 merged 1 commit into
mainfrom
responder

Conversation

@qm012

@qm012 qm012 commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Adds six top-level response helpers that write complete HTTP responses
(headers, status code, body) on top of net/http:

  • JSON(w, statusCode, data, opts...) — encodes with encoding/json;
    options: EscapeForHTML(false) to disable HTML escaping (on by default)
    and Indented(true) for pretty-printed output
  • XML(w, statusCode, data) — marshals with encoding/xml, writes the
    XML declaration; marshaling errors return before any header is sent
  • Text(w, statusCode, s)text/plain; charset=utf-8 via io.WriteString
  • Bytes(w, statusCode, contentType, b) — in-memory raw bytes with a
    caller-supplied content type
  • Stream(w, statusCode, contentType, r)io.Copy from any io.Reader
    with constant memory; takes the sendfile fast path for *os.File.
    Intended for large or not-yet-complete bodies (downloads, proxied
    upstream responses, generated streams); disk files that need Range and
    caching support should use http.ServeFile / http.ServeFileFS
  • Attachment(w, filename, r) — sends any io.Reader as a download
    attachment with 200 OK: Content-Disposition is derived from filename
    (Unicode-safe via RFC 5987 through mime.FormatMediaType), Content-Type
    is inferred from the extension with an application/octet-stream
    fallback; built on Stream

Usage

app := sim.NewApp()

app.Get("/user", func(w http.ResponseWriter, r *http.Request) {
    if err := sim.JSON(w, http.StatusOK, user{Name: "gopher", Age: 5}); err != nil {
        slog.Error("write response", "err", err)
    }
})

// File download: Content-Disposition and Content-Type are derived
// from the filename.
app.Get("/download/{file}", func(w http.ResponseWriter, r *http.Request) {
    name := r.PathValue("file")
    f, err := os.Open(name)
    if err != nil {
        sim.JSON(w, http.StatusNotFound, map[string]string{"message": err.Error()})
        return
    }
    defer f.Close()
    sim.Attachment(w, name, f)
})

@qm012 qm012 self-assigned this Aug 25, 2026
@qm012 qm012 added the enhancement New feature or request label Aug 25, 2026
@qm012

qm012 commented Aug 26, 2026

Copy link
Copy Markdown
Owner Author

related #43

@qm012

qm012 commented Aug 26, 2026

Copy link
Copy Markdown
Owner Author

/lgtm

1 similar comment
@qm012

qm012 commented Aug 26, 2026

Copy link
Copy Markdown
Owner Author

/lgtm

@qm012

qm012 commented Aug 26, 2026

Copy link
Copy Markdown
Owner Author

/hold

@qm012 qm012 changed the title feat: add JSON/XML/Text/Bytes/Stream response helpers feat: add JSON/XML/Text/Bytes/Stream/Attachment response helpers Aug 31, 2026
fix lint

xml fail test case

add Attachment func
@github-actions

Copy link
Copy Markdown

Merging this branch will increase overall coverage

Impacted Packages Coverage Δ 🤖
github.com/qm012/sim 91.27% (+1.53%) 👍

Coverage by file

Changed files (no unit tests)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/qm012/sim/responder.go 100.00% (+100.00%) 41 (+41) 41 (+41) 0 🌟

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files

  • github.com/qm012/sim/responder_test.go

@qm012

qm012 commented Aug 31, 2026

Copy link
Copy Markdown
Owner Author

/lgtm

@qm012
qm012 merged commit 147589c into main Aug 31, 2026
6 checks passed
@qm012
qm012 deleted the responder branch August 31, 2026 09:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant